package com.cyy.demo.utils;

import com.cyy.demo.constant.Constant;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * rest请求的封装类
 * gb
 */
@Component
public class RestHelper {

    private static final Logger logger = LoggerFactory.getLogger(RestHelper.class);

    @Autowired
    public RestTemplate restTemplate;

    private ObjectMapper mapper = new ObjectMapper();

    private String serviceName;

    private String url;

    private HttpServletRequest httpServletRequest;

    public static final String SERVICEDESC = "服务名不能为空";

    public static final String URLDESC = "URL不能为空";

    public static final String REQUESTDESC = "HTTPREQUEST不能为空";

    public RestHelper combinedAssembly(Parameter parameter) {
        this.serviceName = parameter.serviceName;
        this.url = parameter.url;
        this.httpServletRequest = parameter.httpServletRequest;
        return this;
    }


    /**
     * @param url          地址
     * @param serviceName  服务名
     * @param parameter    请求参数
     * @param responseType 返回类型
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public <T> T postForObject(String url, String serviceName, HttpServletRequest httpServletRequest, Object parameter, Class<T> responseType) throws JsonProcessingException {
        checkParameterByAssert();
        this.httpServletRequest = httpServletRequest;
        this.serviceName = serviceName;
        this.url = url;
        String value = mapper.writeValueAsString(parameter);
        HttpEntity<String> requestEntity = new HttpEntity<String>(value, initializationRequestHeads());
        ResponseEntity<T> tResponseEntity = restTemplate.postForEntity(requestUrls(), requestEntity, responseType);
        return tResponseEntity.getBody();
    }

    /**
     * @param url          地址
     * @param serviceName  服务名
     * @param responseType 返回类型
     * @param uriVariables 请求参数
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public <T> T getForObject(String url, String serviceName, HttpServletRequest httpServletRequest, Class<T> responseType, Map<String, ?> uriVariables) throws JsonProcessingException {
        checkParameterByAssert();
        this.httpServletRequest = httpServletRequest;
        this.serviceName = serviceName;
        this.url = url;
        HttpEntity<String> requestEntity = new HttpEntity<String>(initializationRequestHeads());
        ResponseEntity<T> exchange = restTemplate.exchange(requestUrls(), HttpMethod.GET, requestEntity, responseType, uriVariables);
        return exchange.getBody();
    }

    public <T> T postForObject(Class<T> responseType) throws JsonProcessingException {
        HttpEntity<String> requestEntity = getHttpEntity();
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.POST, requestEntity, responseType);
        return tResponseEntity.getBody();
    }

    public <T> ResponseEntity<T> postForEntity(Class<T> responseType) throws JsonProcessingException {
        HttpEntity<String> requestEntity = getHttpEntity();
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.POST, requestEntity, responseType);
        return tResponseEntity;
    }

    public <T> T postForObject(Object parameter, Class<T> responseType) throws JsonProcessingException {
        isNull(serviceName, SERVICEDESC);
        isNull(url, URLDESC);
        String value = mapper.writeValueAsString(parameter);
        logger.info("访问的URL: {},参数: {}", requestUrls(), value);
        HttpEntity<String> requestEntity = new HttpEntity<String>(value, initializationRequestHeads());
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.POST, requestEntity, responseType);
        return tResponseEntity.getBody();
    }

    public <T> T postForFormUrlEncode(Map<String, Object> parameter, Class<T> responseType) throws JsonProcessingException {
        isNull(serviceName, SERVICEDESC);
        isNull(url, URLDESC);
        logger.info("访问的URL: {},参数: {}", requestUrls(), parameter);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        parameter.forEach((k, v) -> {
            List<Object> valueList = Lists.newArrayList();
            valueList.add(v);
            map.put(k, valueList);
        });
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, initEnCodeRequestHeads());
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.POST, requestEntity, responseType);
        return tResponseEntity.getBody();
    }

    public <T> T postForFormData(Map<String, Object> parameter, Class<T> responseType) throws JsonProcessingException {
        isNull(serviceName, SERVICEDESC);
        isNull(url, URLDESC);
        logger.info("访问的URL: {},参数: {}", requestUrls(), parameter);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        parameter.forEach((k, v) -> {
            map.add(k, v);
        });
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, initializationFileRequestHeads());
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.POST, requestEntity, responseType);
        return tResponseEntity.getBody();
    }

    public <T> ResponseEntity<T> postForEntity(Object parameter, Class<T> responseType) throws JsonProcessingException {
        String asString = mapper.writeValueAsString(parameter);
        HttpEntity<String> stringHttpEntity = new HttpEntity<>(asString, initializationRequestHeads());
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.POST, stringHttpEntity, responseType);
        return tResponseEntity;
    }

    /**
     * @param responseType 返回类型
     * @param uriVariables 参数
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public <T> T getForObject(Object uriVariables, Class<T> responseType) throws JsonProcessingException {
        logger.info("访问的URL: {},参数: {}", requestUrls(), uriVariables);
        HttpEntity<String> requestEntity = getHttpEntity();
        ResponseEntity<T> exchange = restTemplate.exchange(requestUrls(), HttpMethod.GET, requestEntity, responseType, uriVariables);
        return exchange.getBody();
    }

    /**
     * 针对get请求url传参的方式
     *
     * @param uriVariables
     * @param responseType
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public <T> T getForUrlParams(Map<String, Object> uriVariables, Class<T> responseType) throws JsonProcessingException {
        HttpEntity<String> requestEntity = getHttpEntity();
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(requestUrls());
        if (!ObjectUtils.isEmpty(uriVariables)) {
            uriVariables.forEach((k, v) -> {
                builder.queryParam(k, v);
            });
        }
        URI uri = builder.build().encode().toUri();
        logger.info("访问的URL: {},参数: {}", uri, uriVariables);
        ResponseEntity<T> exchange = restTemplate.exchange(uri, HttpMethod.GET, requestEntity, responseType);
        return exchange.getBody();
    }

    public <T> ResponseEntity<T> getForEntity(Map<String, ?> uriVariables, Class<T> responseType) throws JsonProcessingException {
        HttpEntity<String> requestEntity = getHttpEntity();
        ResponseEntity<T> exchange = restTemplate.exchange(requestUrls(), HttpMethod.GET, requestEntity, responseType, uriVariables);
        return exchange;
    }

    /**
     * @param responseType 返回类型
     * @param
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public <T> T getForObject(Class<T> responseType) throws JsonProcessingException {
        logger.info("访问的URL: {},参数: {}", requestUrls());
        HttpEntity<String> requestEntity = getHttpEntity();
        ResponseEntity<T> exchange = restTemplate.exchange(requestUrls(), HttpMethod.GET, requestEntity, responseType);
        return exchange.getBody();
    }

    public <T> ResponseEntity<T> getForEntity(Class<T> responseType) throws JsonProcessingException {
        HttpEntity<String> requestEntity = getHttpEntity();
        ResponseEntity<T> exchange = restTemplate.exchange(requestUrls(), HttpMethod.GET, requestEntity, responseType);
        return exchange;
    }


    public <T> T putForObject(Object parameter, Class<T> responseType) throws JsonProcessingException {
        isNull(serviceName, SERVICEDESC);
        isNull(url, URLDESC);
        String value = mapper.writeValueAsString(parameter);
        logger.info("访问的URL: {},参数: {}", requestUrls(), value);
        HttpEntity<String> requestEntity = new HttpEntity<String>(value, initializationRequestHeads());
        ResponseEntity<T> tResponseEntity = restTemplate.exchange(requestUrls(), HttpMethod.PUT, requestEntity, responseType);
        return tResponseEntity.getBody();
    }

    private HttpEntity<String> getHttpEntity() {
        isNull(serviceName, SERVICEDESC);
        isNull(url, URLDESC);
        return new HttpEntity<String>(initializationRequestHeads());
    }

    private HttpHeaders initializationRequestHeads() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        String token = httpServletRequest.getHeader(Constant.TOKEN);
        if (StringUtils.isNotEmpty(token)) {
            headers.add(Constant.TOKEN, token);
        }

        String tokenId = httpServletRequest.getHeader(Constant.TOKEN_ID);
        if (StringUtils.isEmpty(tokenId)) {
            tokenId = httpServletRequest.getAttribute(Constant.TOKEN_ID) + "";
        }
        if (StringUtils.isNotEmpty(tokenId)) {
            List<String> cookies = new ArrayList<>();
            cookies.add(Constant.ACCESS_TOKEN + "=" + tokenId);
            cookies.add(Constant.TOKEN_ID + "=" + tokenId);
            headers.put(HttpHeaders.COOKIE, cookies);
        }

        return headers;
    }

    private HttpHeaders initializationFileRequestHeads() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "multipart/form-data");
        headers.setContentType(MediaType.parseMediaType("multipart/form-data; charset=utf-8"));
        String token = httpServletRequest.getHeader(Constant.TOKEN);
        if (StringUtils.isNotEmpty(token)) {
            headers.add(Constant.TOKEN, token);
        }
        String tokenId = httpServletRequest.getHeader(Constant.TOKEN_ID);
        if (StringUtils.isEmpty(tokenId)) {
            tokenId = httpServletRequest.getAttribute(Constant.TOKEN_ID) + "";
        }
        if (StringUtils.isNotEmpty(tokenId)) {
            List<String> cookies = new ArrayList<>();
            cookies.add(Constant.ACCESS_TOKEN + "=" + tokenId);
            cookies.add(Constant.TOKEN_ID + "=" + tokenId);
            headers.put(HttpHeaders.COOKIE, cookies);
        }
        return headers;
    }

    private HttpHeaders initEnCodeRequestHeads() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/x-www-form-urlencoded");
        headers.setContentType(MediaType.parseMediaType("application/x-www-form-urlencoded; charset=utf-8"));
        String token = httpServletRequest.getHeader(Constant.TOKEN);
        if (StringUtils.isNotEmpty(token)) {
            headers.add(Constant.TOKEN, token);
        }
        String tokenId = httpServletRequest.getHeader(Constant.TOKEN_ID);
        if (StringUtils.isEmpty(tokenId)) {
            tokenId = httpServletRequest.getAttribute(Constant.TOKEN_ID) + "";
        }
        if (StringUtils.isNotEmpty(tokenId)) {
            List<String> cookies = new ArrayList<>();
            cookies.add(Constant.ACCESS_TOKEN + "=" + tokenId);
            cookies.add(Constant.TOKEN_ID + "=" + tokenId);
            headers.put(HttpHeaders.COOKIE, cookies);
        }
        return headers;
    }

    private String requestUrls() {
        return "http://" + serviceName + url;
    }

    private void checkParameterByAssert() {
        isNull(serviceName, SERVICEDESC);
        isNull(url, URLDESC);
    }

    private void isNull(Object o, String message) {
        if (o == null) {
            throw new IllegalArgumentException(o + message);
        }
    }

    public class Parameter {
        private String serviceName;

        private String url;

        private HttpServletRequest httpServletRequest;

        public Parameter addServiceName(String serviceName) {
            this.serviceName = serviceName;
            return this;
        }

        public Parameter addUrl(String url) {
            this.url = url;
            return this;
        }

        public Parameter addHttpServletRequest(HttpServletRequest httpServletRequest) {
            this.httpServletRequest = httpServletRequest;
            return this;
        }

    }
}
